package com.whfc.uni.service.impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.file.properties.FileExpirationRules;
import com.whfc.common.result.PageData;
import com.whfc.common.spring.AppContextUtil;
import com.whfc.common.util.CollectionUtil;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.common.util.RandomUtil;
import com.whfc.entity.dto.OssPathDTO;
import com.whfc.fuum.service.SysDeptService;
import com.whfc.uni.dao.CarInoutRecordMapper;
import com.whfc.uni.dto.*;
import com.whfc.uni.entity.CarInoutRecord;
import com.whfc.uni.enums.Direction;
import com.whfc.uni.event.CarDataSyncEvent;
import com.whfc.uni.service.CarInoutRecordService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.io.FileInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : qzexing
 * @version : 1.0
 * @date : 2020/6/22 15:13
 */
@DubboService(interfaceClass = CarInoutRecordService.class, version = "1.0.0", timeout = 30 * 1000)
public class CarInoutRecordServiceImpl implements CarInoutRecordService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private CarInoutRecordMapper carInoutRecordMapper;

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @Autowired
    private FilePathConfig filePathConfig;

    @Autowired
    private FileHandler fileHandler;

    @Override
    public void saveRecord(CarInoutRecordDTO carInoutRecordDTO) {
        logger.info("新增记录 图片地址方式,carInoutRecordDTO:{}", carInoutRecordDTO);
        CarInoutRecord carInRecord = new CarInoutRecord();
        BeanUtils.copyProperties(carInoutRecordDTO, carInRecord);
        carInoutRecordMapper.insertSelective(carInRecord);
    }

    @Override
    public PageData<CarInoutRecordDTO> getRecordList(Integer deptId, Date date, String licensePlate, String deviceName, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<CarInoutRecordDTO> list = carInoutRecordMapper.selectRecordList(deptId, date, licensePlate, deviceName);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public PageData<CarInoutRecordDTO> getRecordList(Integer deptId, Date startTime, Date endTime, Integer pageNum, Integer pageSize) {
        logger.info("车辆统计列表，deptId：{}，startTime：{}，endTime：{},pageNum；{}，pageSize：{}", deptId, startTime, endTime, pageNum, pageSize);
        startTime = DateUtil.getDateBegin(startTime);
        endTime = DateUtil.getDateEnd(endTime);
        PageHelper.startPage(pageNum, pageSize);
        List<CarInoutRecordDTO> list = carInoutRecordMapper.selectRecordListByDeptId(deptId, startTime, endTime);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public CarStatisticalDTO getDayStatistical(Integer deptId, Date startTime, Date endTime) throws BizException {
        logger.info("车辆统计（天）deptId：{}，startTime：{}，endTime：{}", deptId, startTime, endTime);
        List<CarLicensePlateStatisticalDTO> licensePlateList = carInoutRecordMapper.selectCarLicensePlateStatistical(deptId, startTime, endTime);
        Integer total = 0;
        if (licensePlateList != null) {
            total = licensePlateList.stream().mapToInt(CarLicensePlateStatisticalDTO::getNum).sum();
        }
        List<CarHourStatisticalDTO> list = carInoutRecordMapper.selectCarHourStatistical(deptId, startTime, endTime);

        List<CarHourStatisticalDTO> carList = carInoutRecordMapper.selectHourStatistical(deptId, startTime, endTime);
        List<Date> times = DateUtil.getHourListBetween(startTime, endTime);
        times.add(0, times.get(times.size() - 1));
        times.remove(times.size() - 1);
        List<CarHourStatisticalDTO> timeList = new ArrayList<>();
        List<CarHourStatisticalDTO> carHourList = new ArrayList<>();
        if (list != null) {
            times.forEach(date -> {
                CarHourStatisticalDTO dto = new CarHourStatisticalDTO();
                dto.setHour(date);
                dto.setNum(0);
                list.forEach(carHourStatisticalDTO -> {
                    String timeStr1 = DateUtil.formatDate(carHourStatisticalDTO.getHour(), "yyyy-MM-dd HH:00:00");
                    String timeStr2 = DateUtil.formatDate(date, "yyyy-MM-dd HH:00:00");
                    if (timeStr1.equals(timeStr2)) {
                        dto.setNum(carHourStatisticalDTO.getNum());
                    }
                });
                CarHourStatisticalDTO dto1 = new CarHourStatisticalDTO();
                dto1.setHour(date);
                dto1.setNum(0);
                carList.forEach(carHourStatisticalDTO -> {
                    String timeStr1 = DateUtil.formatDate(carHourStatisticalDTO.getHour(), "yyyy-MM-dd HH:00:00");
                    String timeStr2 = DateUtil.formatDate(date, "yyyy-MM-dd HH:00:00");
                    if (timeStr1.equals(timeStr2)) {
                        dto1.setNum(carHourStatisticalDTO.getNum());
                    }
                });
                timeList.add(dto);
                carHourList.add(dto1);
            });
        }
        CarStatisticalDTO carStatisticalDTO = new CarStatisticalDTO();
        carStatisticalDTO.setLicensePlateList(licensePlateList);
        carStatisticalDTO.setTimeList(timeList);
        carStatisticalDTO.setCarList(carHourList);
        carStatisticalDTO.setTotal(total);
        return carStatisticalDTO;
    }

    @Override
    public CarStatisticalDTO getMonthStatistical(Integer deptId, Date startTime, Date endTime) throws BizException {
        logger.info("车辆统计（月）deptId：{}，startTime：{}，endTime：{}", deptId, startTime, endTime);
        List<CarLicensePlateStatisticalDTO> licensePlateList = carInoutRecordMapper.selectCarLicensePlateStatistical(deptId, startTime, endTime);
        Integer total = 0;
        if (licensePlateList != null) {
            total = licensePlateList.stream().mapToInt(CarLicensePlateStatisticalDTO::getNum).sum();
        }
        List<CarHourStatisticalDTO> list = carInoutRecordMapper.selectCarHourStatistical(deptId, startTime, endTime);
        List<CarHourStatisticalDTO> carList = carInoutRecordMapper.selectMothCarHourStatistical(deptId, startTime, endTime);
        List<Date> times = DateUtil.getDayList(startTime, endTime);
        List<CarHourStatisticalDTO> timeList = new ArrayList<>();
        List<CarHourStatisticalDTO> carTimeList = new ArrayList<>();
        if (list != null) {
            times.forEach(date -> {
                CarHourStatisticalDTO dto = new CarHourStatisticalDTO();
                dto.setTime(date);
                dto.setNum(0);
                list.forEach(carHourStatisticalDTO -> {
                    String timeStr1 = DateUtil.formatDate(carHourStatisticalDTO.getHour(), "yyyy-MM-dd");
                    String timeStr2 = DateUtil.formatDate(date, "yyyy-MM-dd");
                    if (timeStr1.equals(timeStr2)) {
                        dto.setNum(carHourStatisticalDTO.getNum());
                    }
                });
                CarHourStatisticalDTO dto1 = new CarHourStatisticalDTO();
                dto1.setTime(date);
                dto1.setNum(0);
                carList.forEach(carHourStatisticalDTO -> {
                    String timeStr1 = DateUtil.formatDate(carHourStatisticalDTO.getTime(), "yyyy-MM-dd");
                    String timeStr2 = DateUtil.formatDate(date, "yyyy-MM-dd");
                    if (timeStr1.equals(timeStr2)) {
                        dto1.setNum(carHourStatisticalDTO.getNum());
                    }
                });
                timeList.add(dto);
                carTimeList.add(dto1);
            });
        }
        CarStatisticalDTO carStatisticalDTO = new CarStatisticalDTO();
        carStatisticalDTO.setLicensePlateList(licensePlateList);
        carStatisticalDTO.setTimeList(timeList);
        carStatisticalDTO.setCarList(carTimeList);
        carStatisticalDTO.setTotal(total);
        return carStatisticalDTO;
    }

    @Override
    public OssPathDTO export(Integer deptId, Date startTime, Date endTime) {
        logger.info("导出车辆记录deptId：{}，startTime：{}，endTime：{}", deptId, startTime, endTime);
        List<CarInoutRecordDTO> list = carInoutRecordMapper.selectRecordListByDeptId(deptId, startTime, endTime);
        String deptName = sysDeptService.getDeptNameById(deptId);
        OssPathDTO ossPathDTO = new OssPathDTO();
        try {
            String startTimeStr = DateUtil.formatDate(startTime, "yyyy年MM月dd日");

            //写数据
            File destFile = File.createTempFile(RandomUtil.getRandomFileName(), ".xlsx");
            ClassPathResource resource = new ClassPathResource("templates/CarInoutRecordTemplate.xlsx");
            ExcelWriter excelWriter = EasyExcel.write(destFile)
                    .withTemplate(resource.getInputStream()).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            Map<String, Object> map = new HashMap<>(3);
            map.put("deptName", deptName);
            map.put("date", startTimeStr);
            excelWriter.fill(map, writeSheet);

            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(list, fillConfig, writeSheet);
            excelWriter.finish();

            //上传oss
            String filepath = filePathConfig.getFilePath(String.format("car/inoutRecord/%s车辆出入记录.xls", startTimeStr));
            String upload = fileHandler.upload(filepath, new FileInputStream(destFile), FileExpirationRules.DAYS_1);
            ossPathDTO.setPath(upload);
        } catch (Exception e) {
            logger.error("导出车辆记录失败", e);
        }
        logger.info("导出文件:{}", ossPathDTO.getPath());
        return ossPathDTO;
    }

    @Override
    public CarLogDTO carLog(Integer deptId, Date date) {
        logger.info("车辆日志：deptId：{}，date：{}", deptId, date);
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);
        List<CarLicensePlateStatisticalDTO> licensePlateList = carInoutRecordMapper.selectCarLog(deptId, startTime, endTime);
        licensePlateList = licensePlateList.stream().sorted(Comparator.comparingInt(CarLicensePlateStatisticalDTO::getNum)
                .reversed()).collect(Collectors.toList());
        CarLogDTO carLogDTO = new CarLogDTO();
        carLogDTO.setCarNum(0);
        carLogDTO.setLicensePlateList(licensePlateList);
        if (licensePlateList != null && !licensePlateList.isEmpty()) {
            carLogDTO.setCarNum(licensePlateList.size());
        }
        return carLogDTO;
    }

    @Override
    public CarBoardAnalysisDTO boardAnalysis(Integer deptId, Date startTime, Date endTime) throws BizException {
        logger.info("车辆大屏统计，deptId：{}，startTime：{}，endTime：{}", deptId, startTime, endTime);
        if (endTime != null) {
            endTime = DateUtil.getDateEnd(endTime);
        }
        CarBoardAnalysisDTO data = carInoutRecordMapper.selectBoardAnalysis(deptId, startTime, endTime);
        if (data == null) {
            data = new CarBoardAnalysisDTO();
            data.setInNum(0);
            data.setOutNum(0);
        }
        List<CarInoutRecordDTO> records = carInoutRecordMapper.selectRecordListByDeptId(deptId, startTime, endTime);
        data.setRecords(records.stream().limit(20).collect(Collectors.toList()));
        return data;
    }

    @Override
    public CarBoardAnalysisDTO boardAnalysis2(Integer deptId, Date startTime, Date endTime) throws BizException {
        logger.info("车辆大屏统计，deptId：{}，startTime：{}，endTime：{}", deptId, startTime, endTime);
        if (endTime != null) {
            endTime = DateUtil.getDateEnd(endTime);
        }
        List<CarInoutRecordDTO> inList = carInoutRecordMapper.selectRecordListByDeptIdAndDirection(deptId, Direction.IN.getValue(), startTime, endTime);
        List<CarInoutRecordDTO> outList = carInoutRecordMapper.selectRecordListByDeptIdAndDirection(deptId, Direction.OUT.getValue(), startTime, endTime);

        Map<String, List<CarInoutRecordDTO>> inMap = CollectionUtil.groupBy(inList, CarInoutRecordDTO::getLicensePlate);
        Map<String, List<CarInoutRecordDTO>> outMap = CollectionUtil.groupBy(outList, CarInoutRecordDTO::getLicensePlate);

        Set<String> licenseSet = new TreeSet<>();
        licenseSet.addAll(inMap.keySet());
        licenseSet.addAll(outMap.keySet());
        logger.info("车牌号集合:{}", licenseSet);

        List<CarInoutRecordDTO> records = new ArrayList<>(licenseSet.size());
        for (String license : licenseSet) {
            CarInoutRecordDTO recordDTO = null;
            if (inMap.containsKey(license)) {
                List<CarInoutRecordDTO> inRecordList = inMap.get(license);
                recordDTO = recordDTO == null ? inRecordList.get(0) : recordDTO;
                recordDTO.setInTime(inRecordList.get(0).getTime());
                recordDTO.setInImgUrl(inRecordList.get(0).getImgUrl());
                recordDTO.setDirection(null);
                recordDTO.setTime(null);
                recordDTO.setImgUrl(null);
            }
            if (outMap.containsKey(license)) {
                List<CarInoutRecordDTO> outRecordList = outMap.get(license);
                recordDTO = recordDTO == null ? outRecordList.get(0) : recordDTO;
                recordDTO.setOutTime(outRecordList.get(0).getTime());
                recordDTO.setOutImgUrl(outRecordList.get(0).getImgUrl());
                recordDTO.setDirection(null);
                recordDTO.setTime(null);
                recordDTO.setImgUrl(null);
            }
            records.add(recordDTO);
        }
        CarBoardAnalysisDTO data = new CarBoardAnalysisDTO();
        data.setInNum(inList.size());
        data.setOutNum(outList.size());
        data.setRecords(records.stream().limit(20).collect(Collectors.toList()));
        return data;
    }
}
